package com.colin.jipay.starpos;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.util.Log;

import com.blankj.utilcode.util.AppUtils;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.SPUtils;
import com.blankj.utilcode.util.StringUtils;
import com.blankj.utilcode.util.TimeUtils;
import com.blankj.utilcode.util.ToastUtils;
import com.colin.jipay.starpos.bean.PushStarPosBean;
import com.colin.jipay.starpos.bean.TransactionQueryBean;
import com.colin.jipay.starpos.bean.TransactionQueryRspBean;
import com.colin.jipay.starpos.bean.TransactionQueryStoreBean;
import com.colin.jipay.starpos.bean.TransactionQueryStoreRspBean;
import com.colin.jipay.starpos.bean.TrsacnQryStoreQuestBean;
import com.colin.jipay.starpos.bean.UserBean;
import com.colin.jipay.utils.GsonUtils;
import com.colin.jipay.utils.Util;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.callback.StringCallback;
import com.lzy.okgo.model.Response;

import org.json.JSONObject;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;

public class StarPosHelper {
    public static final String PACKAGE_NAME_FAST_DEV_PRO="com.mohe.fastdevpro_test";
    public static final String PACKAGE_NAME_STAR_POS="com.newland.satrpos.starposmanager";
    public static final String SPLASH_ACTIVITY_NAME="com.mohe.fastdevpro.ui.activity.SplashActivity";

    public static final String CLS_TRANS_ACTION_QUERY="com.newland.satrpos.starposmanager.module.home.transactionquery.TransactionQueryPresenter";
    public static final String METHOD_QUERY_TRANSFER_MONEY ="queryTransferMoney";

    public static final String ACTIVITY_TRANS_QUERY="com.newland.satrpos.starposmanager.module.home.transactionquery.TransactionQueryActivity";
    public static final String METHOD_ACTIVITY_QUERY_TRANSFER="queryTransaction";

    public static final String BEAN_TRANS_ACTION_QUERY_RSP="com.newland.satrpos.starposmanager.model.responsebean.TransactionQueryRspBean";

    public static final String STR_ON_CREATE="onCreate";

    public static final String baseUrl="https://gateway.starpos.com.cn";
    public static final String QryTranListUrl=baseUrl+"/estmadp2/qrytran_list.json";
    public static final String PushStarPosDataUrl="http://43.255.28.117:9090/pay/v1/crawler/hdy.do";

    public static final String LastQueryRspBean="lastQueryRspBean";
    public static final String StrLastQueryStoreHashMap="StrLastQueryStoreHashMap";
    public static List<TransactionQueryStoreBean> newStoreTrans=new ArrayList<>();

    public static Object instanceQueryPresenterClass;
    public static Object instanceQueryActivity;

    public static boolean isScheduling;//是否正在执行循环的逻辑

    public static boolean isInitPrepare=false;
    public static Handler handler;

    public static int scheduleTaskCnt =0;

    public static Application APP_STOR_POS;
    public static UserBean userBean;
    public StarPosHelper() {
    }

    /**
     * 星管家的查询交易presenter类里面的接口
     */
    public static void hookStarPosQueryTrans(final XC_LoadPackage.LoadPackageParam lpparam, final Class hookClass) {
        XposedBridge.log("hookStarPosQueryTrans");

        XposedHelpers.findAndHookMethod(hookClass
                , StarPosHelper.METHOD_QUERY_TRANSFER_MONEY
                , new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        super.beforeHookedMethod(param);
                        XposedBridge.log("调用了星管家的查询交易接口，beforeHookedMethod,"+param.toString());
                        Class c= instanceQueryPresenterClass.getClass().getSuperclass();
                        Field fieldView=c.getDeclaredField("mView");
                        Field fieldGuid=c.getDeclaredField("mGuid");
                        fieldView.setAccessible(true);
                        fieldGuid.setAccessible(true);
                        Object mView=fieldView.get(instanceQueryPresenterClass);
                        Object mGuid=fieldGuid.get(instanceQueryPresenterClass);
                    }
                });
    }

    /**
     * hook查询交易记录的页面的查询方法
     * @param lpparam xposed框架提供的工具参数
     * @param hookClass transActionQuery的方法
     */
    public static void hookActivityStarPosQueryTrans(final XC_LoadPackage.LoadPackageParam lpparam, final Class hookClass) {
        Class<?> clsBeanTrans = XposedHelpers.findClass(StarPosHelper.BEAN_TRANS_ACTION_QUERY_RSP,lpparam.classLoader);
        Object beanTrans=XposedHelpers.newInstance(clsBeanTrans);
        XposedHelpers.findAndHookMethod(hookClass
                , StarPosHelper.METHOD_ACTIVITY_QUERY_TRANSFER
                ,beanTrans.getClass()
                , new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        XposedBridge.log("hookActivityStarPosQueryTrans,beforeHookedMethod,"+param.toString());
                        Object data=param.args[0];
                        String json= GsonUtils.toJson(data);
                        XposedBridge.log(json);
                        instanceQueryActivity=param.thisObject;
                        if (!isInitPrepare){
                            isInitPrepare=true;
                            APP_STOR_POS=((Activity) instanceQueryActivity).getApplication();
                            String strUserBean=GsonUtils.toJson(XposedHelpers.getObjectField(APP_STOR_POS,"a"));
                            StarPosHelper.userBean= GsonUtils.fromJson(strUserBean,UserBean.class);
                            instanceQueryPresenterClass=XposedHelpers.getObjectField(instanceQueryActivity,"mPresenter");
                            handler=new Handler(((Activity)instanceQueryActivity).getMainLooper());
                        }

                        if (StarPosHelper.scheduleTaskCnt==0){
                            TransactionQueryRspBean transRspBean= GsonUtils.fromJson(json,TransactionQueryRspBean.class);
                            if (StarPosHelper.isTransDataChange(transRspBean)){
                                StarPosHelper.getStoeNewTrans(transRspBean);
                            }
                        }
                        handler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                XposedBridge.log("间隔两秒执行queryTrans的方法");
                                try {
                                    if (!Util.isActivityUseable((Activity) instanceQueryActivity)) {
                                        return;
                                    }
                                    XposedHelpers.callMethod(instanceQueryPresenterClass, StarPosHelper.METHOD_QUERY_TRANSFER_MONEY);
                                } catch (Exception e){
                                    XposedBridge.log(e.getMessage());
                                }
                            }
                        },2000);
                    }
                });
    }

    /**
     * 循环执行交易查询页面的查询方法
     * @param instanceQueryPresenterClass 查询页面的presenter类实例对象
     */
    public static void scheduleQueryTrans(final Object instanceQueryPresenterClass){
        Class<?> clzQryTraPresent = null;
        ClassLoader classLoader=instanceQueryPresenterClass.getClass().getClassLoader();
        try {
            clzQryTraPresent = classLoader.loadClass(StarPosHelper.CLS_TRANS_ACTION_QUERY);
        } catch (Exception e) {
            Log.e("jyy", "寻找"+ StarPosHelper.CLS_TRANS_ACTION_QUERY+"报错", e);
            return;
        }

        //找到类里面的查询交易方法
        final Method methodQueryTrans=XposedHelpers.findMethodBestMatch(clzQryTraPresent, StarPosHelper.METHOD_QUERY_TRANSFER_MONEY);
        final Class<?> finalClzQryTraPresent = clzQryTraPresent;
        //循环调用查询交易方法
        new Thread(new Runnable() {
            @Override
            public void run() {
                Timer timer=new Timer();
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        XposedBridge.log("间隔两秒执行queryTrans的方法");
                        XposedBridge.log("hookClass="+ finalClzQryTraPresent.getName());
                        try {
                            methodQueryTrans.invoke(instanceQueryPresenterClass);
                        } catch (Exception e){
                            XposedBridge.log(e.getMessage());
                        }
                    }
                },2000);
            }
        }).start();
    }

    private static final String TAG = "MyXposedHelper";

    public interface OnCallback<T>{
        void onSuccess(T t);
    }

    public interface OnInitAppCallback{
        void onSuccess(Class hookclass);
    }

    /**
     * 判断交易数据是否有变，通过tot_cnt总交易数判断
     * @param queryRspBean
     * @return true:有变
     */
    public static boolean isTransDataChange(TransactionQueryRspBean queryRspBean){
        String strLastQueryRspBean= SPUtils.getInstance(userBean.getNumber()).getString(LastQueryRspBean);
        TransactionQueryRspBean lastQuerRspBean= GsonUtils.fromJson(strLastQueryRspBean,TransactionQueryRspBean.class);
        String lastTotCnt=lastQuerRspBean.getTot_cnt();
        String nowTotCnt=queryRspBean.getTot_cnt();
        return !lastTotCnt.equals(nowTotCnt) ;
    }

    /**先判断tot_cnt是否有变，不变就过
     有变，循环从商户下的商店中判断每个商店bean的toto_txn_cnt是否有变，
     有变，获取对应的数值，就取出该商店下的前n+5个订单数据，从本地取出该商店的历史最新数据，比对是哪一个，取出剩下的前面的数据进行发送，
     记录最新的一个数据到本地保存。即外面的商店列表的接口只是判断是否有变，具体发送什么数据，由获取商店订单的数据进行判断是最新才发送。
     在循环未结束时，停止获取新数据。 对获取到的数据整合发送到服务端。

     * 通过所有商铺的数据进行查询新的交易数据.
     * @param queryRspBean 商户数据
     */
    public static void getStoeNewTrans(final TransactionQueryRspBean queryRspBean){
        String strLastQueryRspBean= SPUtils.getInstance(userBean.getNumber()).getString(LastQueryRspBean);
        SPUtils.getInstance(userBean.getNumber()).put(LastQueryRspBean,GsonUtils.toJson(queryRspBean));
        TransactionQueryRspBean lastQuerRspBean= GsonUtils.fromJson(strLastQueryRspBean,TransactionQueryRspBean.class);
        List<TransactionQueryBean> lastQueryBeans=lastQuerRspBean.getQryList();

//        final TransactionQueryBean queryBean=queryRspBean.getQryList().get(0);
//        getStoeNewTrans(queryBean, 5, new OnCallback<TransactionQueryStoreRspBean>() {
//            @Override
//            public void onSuccess(TransactionQueryStoreRspBean transactionQueryStoreRspBean) {
//                List<TransactionQueryStoreBean> queryStoreBeans= getNewQueryStoresCompareLocal(transactionQueryStoreRspBean,queryBean.getMerc_id());
//                for (int i=0;i<queryStoreBeans.size();i++){
//                    LogUtils.i(GsonUtils.toJson(queryStoreBeans.get(i)));
//                }
//
//            }
//        });

        List<TransactionQueryBean> queryBeans=queryRspBean.getQryList();
        for (int i=0;i<queryBeans.size();i++){
            final TransactionQueryBean queryBean= queryBeans.get(i);
            TransactionQueryBean lastQryBean=getQueryBeanByMercId(queryBean.getMerc_id(),lastQueryBeans);

            String nowCnt=queryBean.getTot_txn_cnt();
            String lastCnt=lastQryBean.getTot_txn_cnt();
            //本地没数据，就查询该商铺的交易数据
            if (StringUtils.isEmpty(lastCnt)) lastCnt="0";
            int diffCnt=0;
            try {
                diffCnt=Integer.parseInt(nowCnt)-Integer.parseInt(lastCnt);
            }catch (Exception e){
                XposedBridge.log(e.getMessage());
            }

            //如果交易笔数和历史的不一样就开始查询该店铺的数据
            if (diffCnt>0){
                scheduleTaskCnt++;
                getStoeNewTrans(queryBean, diffCnt, new OnCallback<TransactionQueryStoreRspBean>() {
                    @Override
                    public void onSuccess(TransactionQueryStoreRspBean transactionQueryStoreRspBean) {
                        XposedBridge.log(GsonUtils.toJson(transactionQueryStoreRspBean));
                        //和本地的数据进行比对获取最新的交易记录
                        List<TransactionQueryStoreBean> queryStoreBeans=getNewQueryStoresCompareLocal(transactionQueryStoreRspBean,queryBean.getMerc_id());
                        for (int i=0;i<queryStoreBeans.size();i++){
                            queryStoreBeans.get(i).setMerc_id(queryBean.getMerc_id());
                        }
                        pushNewStoreTransToNet(queryStoreBeans);
                    }
                });
            }
        }
    }

    /**
     * 发送数据到服务端
     * @param queryStoreBeans
     */
    private static void pushNewStoreTransToNet(List<TransactionQueryStoreBean> queryStoreBeans) {
        newStoreTrans.addAll(queryStoreBeans);
        LogUtils.i("scheduleTaskCnt="+scheduleTaskCnt);
        if (scheduleTaskCnt!=0) return;
        List<PushStarPosBean> pushStarPosBeans= convertStarPosBean(newStoreTrans);
        LogUtils.i(GsonUtils.toJson(pushStarPosBeans));
        Intent intent=new Intent("com.startPos.getNewOrder");
        intent.putExtra("orders",GsonUtils.toJson(pushStarPosBeans));
        ((Context)instanceQueryActivity).sendBroadcast(intent);
//        OkGo.<String>post(PushStarPosDataUrl)
//                .params("bills",GsonUtils.toJson(pushStarPosBeans))
//                .execute(new StringCallback() {
//                    @Override
//                    public void onSuccess(Response<String> response) {
//                        LogUtils.i(response.body());
//                    }
//                });
    }

    private static List<PushStarPosBean> convertStarPosBean(List<TransactionQueryStoreBean> newStoreTrans) {
        List<PushStarPosBean> starPosBeans=new ArrayList<>();
        for (int i=0;i<newStoreTrans.size();i++){
            TransactionQueryStoreBean queryStoreBean= newStoreTrans.get(i);

            PushStarPosBean starPosBean=new PushStarPosBean();
            starPosBean.setMch_id(queryStoreBean.getMerc_id());
            starPosBean.setMch(queryStoreBean.getStoe_nm());
            starPosBean.setBill_no(queryStoreBean.getLog_no());
            starPosBean.setPay_money(queryStoreBean.getTxn_amt());
            starPosBean.setPay_time(queryStoreBean.getTxn_tm());
            starPosBean.setPay_type(getPaychannel(queryStoreBean.getPaytype()));
            starPosBean.setMark(queryStoreBean.getTxn_desc());

            starPosBeans.add(starPosBean);
        }

        return starPosBeans;
    }

    /**
     * 是否循环获取商铺列表里面的商铺交易数据结束
     * @return
     */
    public static boolean isScheduleGetStoreTransOver(){
        return scheduleTaskCnt==0;
    }

    /**
     * 通过店铺数据，获取该店铺下的交易数据
     * @param queryBean 店铺数据
     * @param cnt 需要查询的数量
     *{
    "usr_no": "00000241389",
    "token_id": "XqnOWV1Bg7aqM5E72I91zYNKb577R2i7",
    "end_dt": "20190509235900",
    "eqm_type": "nubia",
    "pag_size": "10",
    "characterSet": "GBK",
    "beg_dt": "20190501000000",
    "merc_id": "800318000001013",
    "contentTyp": "application/json",
    "pag_no": "1",
    "sys_cnl": "app",
    "txn_cd": "",
    "stoe_id": "101318057220005",
    "trm_no": "",
    "version": "3.0.0",
    "sn_no": "",
    "opSys": "0",
    "channel": "oppo",
    "usr_typ": "0",
    "pay_type": ""
    }
     */
    private static void getStoeNewTrans(TransactionQueryBean queryBean, int cnt, final OnCallback<TransactionQueryStoreRspBean> callback) {
        Map<String, String> hashMap = new HashMap(16);
        hashMap.put("stoe_id", queryBean.getStoe_id());
        hashMap.put("merc_id", queryBean.getMerc_id());
        TrsacnQryStoreQuestBean requestBean=setRequestBean(queryBean);

        hashMap.put("usr_typ", requestBean.getUsr_typ());
        hashMap.put("beg_dt", requestBean.getBeg_dt());
        hashMap.put("end_dt", requestBean.getEnd_dt());
        hashMap.put("txn_cd", requestBean.getTxn_cd());
        hashMap.put("pay_type",requestBean.getPay_type());
        hashMap.put("trm_no",requestBean.getTrm_no());
        hashMap.put("sn_no",requestBean.getSn_no());
        hashMap.put("pag_no", String.valueOf(1));
        hashMap.put("pag_size", String.valueOf(cnt+5));
        setCommonReqParams(hashMap);

        OkGo.<String>post(QryTranListUrl)
                .upJson(new JSONObject(hashMap))
                .execute(new StringCallback() {
                    @Override
                    public void onSuccess(Response<String> response) {
                        ToastUtils.showLong(response.body());
                        LogUtils.i(response.body());
                        scheduleTaskCnt--;
                        callback.onSuccess(GsonUtils.fromJson(response.body(),TransactionQueryStoreRspBean.class));
                    }

                    @Override
                    public void onError(Response<String> response) {
                        super.onError(response);
                        scheduleTaskCnt--;
                    }
                });

    }


    public static TrsacnQryStoreQuestBean setRequestBean(TransactionQueryBean queryBean) {
        String mEndDate = getTimeToStr(TimeUtils.getNowDate(), "yyyyMMdd") + "235900";
        String mBegDate =getTimeToStr(TimeUtils.getNowDate(), "yyyyMMdd")  + "000000";

        TrsacnQryStoreQuestBean trsacnQryStoreQuestBean = new TrsacnQryStoreQuestBean();
        trsacnQryStoreQuestBean.setMerc_id(queryBean.getMerc_id());
        trsacnQryStoreQuestBean.setBeg_dt(mBegDate);
        trsacnQryStoreQuestBean.setEnd_dt(mEndDate);
        trsacnQryStoreQuestBean.setUsr_typ(userBean.getType());
        trsacnQryStoreQuestBean.setTrm_no("");
        trsacnQryStoreQuestBean.setPay_type("");
        trsacnQryStoreQuestBean.setTxn_cd("");
        trsacnQryStoreQuestBean.setSn_no("");
        return trsacnQryStoreQuestBean;
    }

    public static Map<String,String> setCommonReqParams(Map<String,String> map){
        map.put("contentTyp", "application/json");
        map.put("opSys", "0");
        map.put("characterSet", "GBK");
        map.put("sys_cnl", "app");
        String versionName = AppUtils.getAppVersionName(PACKAGE_NAME_STAR_POS);

        if (versionName.contains("-debug")) {
            map.put("version", versionName.substring(0, versionName.indexOf("-")));
        } else {
            map.put("version", versionName);
        }
        map.put("token_id", userBean.getToken_id());
        map.put("usr_no", userBean.getNumber());
        map.put("channel", "oppo");
        map.put("eqm_type", Build.MANUFACTURER);
        return map;
    }

    /**
     * 通过店铺id获取所有店铺列表里面对应的店铺数据
     * @param merc_id 店铺id
     * @param queryBeans 所有店铺列表
     * @return 对应的店铺
     */
    public static TransactionQueryBean getQueryBeanByMercId(String merc_id,List<TransactionQueryBean> queryBeans){
        for (int i=0;i<queryBeans.size();i++){
            TransactionQueryBean queryBean=queryBeans.get(i);
            if (merc_id.equals(queryBean.getMerc_id())){
                return queryBean;
            }
        }
        return new TransactionQueryBean();
    }

    /**
     * 此商铺下的所有交易数据和本地保存的上一个最新数据进行对比,取出这个数据时间线之后的所有数据
     * @param storeRspBean 该商铺下查询到的一定数量的交易数据(查到的应该是1天时间内的)
     * @param merc_id 该商铺Id
     * @return 最新的数据
     */
    public static List<TransactionQueryStoreBean> getNewQueryStoresCompareLocal(TransactionQueryStoreRspBean storeRspBean,String merc_id){
        List<TransactionQueryStoreBean> newQueryStoreBeans=storeRspBean.getStoeTxnList();
        //每个账号表示一个商户，一个商户下有很多个商铺
        String strStoreBeanHashMap=SPUtils.getInstance(userBean.getNumber()).getString(StrLastQueryStoreHashMap);

        //本地保存的是一个商铺下对应的历史最新的一条数据的hashMap
        Map<String,String> lastStoreBeanHashMap= Util.jsonToMap(strStoreBeanHashMap);
        String strLastStoreBean=lastStoreBeanHashMap.get(merc_id);

        TransactionQueryStoreBean lastQueryStoreBean=GsonUtils.fromJson(strLastStoreBean,TransactionQueryStoreBean.class);

        //保存该商铺下的最新一条数据到sp，key值为该商铺id
        lastStoreBeanHashMap.put(merc_id,GsonUtils.toJson(newQueryStoreBeans.get(0)));
        SPUtils.getInstance(userBean.getNumber())
                .put(StrLastQueryStoreHashMap
                        ,new JSONObject(lastStoreBeanHashMap).toString());

        //如果本地没有保存数据，就把获取到的所有新数据发送到服务端
        if (lastQueryStoreBean!=null) return newQueryStoreBeans;

        for (int i=0;i<newQueryStoreBeans.size();i++){
            TransactionQueryStoreBean storeBean=newQueryStoreBeans.get(i);
            if (storeBean.getLog_no().equals(lastQueryStoreBean.getLog_no())){
                return newQueryStoreBeans.subList(0,i);
            }
        }
        return newQueryStoreBeans;
    }

    @SuppressLint({"SimpleDateFormat"})
    public static String getTimeToStr(Date date, String str) {
        String str2 = "";
        if (date != null) {
            return new SimpleDateFormat(str).format(date);
        }
        return str2;
    }

    /**
     * 根据paytype的字符串得到对应的明文支付渠道
     * @param str 支付类型
     * @return
     */
    public static String getPaychannel(String str) {
        char c = 65535;
        switch (str.hashCode()) {
            case 49:
                if (str.equals("1")) {
                    c = 0;
                    break;
                }
                break;
            case 50:
                if (str.equals("2")) {
                    c = 1;
                    break;
                }
                break;
            case 51:
                if (str.equals("3")) {
                    c = 2;
                    break;
                }
                break;
            case 57:
                if (str.equals("9")) {
                    c = 3;
                    break;
                }
                break;
            case 1567:
                if (str.equals("10")) {
                    c = 6;
                    break;
                }
                break;
            case 1568:
                if (str.equals("11")) {
                    c = 7;
                    break;
                }
                break;
            case 1569:
                if (str.equals("12")) {
                    c = 8;
                    break;
                }
                break;
            case 442934545:
                if (str.equals("4433100")) {
                    c = 5;
                    break;
                }
                break;
            case 1077101254:
                if (str.equals("GTXYPOS")) {
                    c = 4;
                    break;
                }
                break;
        }
        switch (c) {
            case 0:
                return "支付宝扫码";
            case 1:
                return "微信扫码";
            case 2:
                return "会员卡支付";
            case 3:
                return "银联二维码";
            case 4:
                return "银行卡";
            case 5:
                return "现金";
            case 6:
                return "会员积分";
            case 7:
            case 8:
                return "星币支付";
            default:
                return "其他";
        }
    }

}
